<script lang="ts" setup>
import { apiMenu } from "@/api/sys";
import iconPickerVue from "@/components/icon-picker-vxe.vue";
import { useMessage } from "@/hooks/web/use-message";
import { MenuBehavior, MenuType, type Form, type MenuInfo } from "@/models";
import { reactive, ref } from "vue";
import { type VxeFormInstance, type VxeFormProps, type VxeModalInstance, type VxeModalListeners, type VxeModalProps } from "vxe-table";

//#region [state]
type PageState = { value?: MenuInfo; parent?: MenuInfo; title: string; show: boolean };
const page = reactive<PageState>({ title: "新增菜单", show: false });
const emit = defineEmits<{ (event: "onsaved", value?: Nullable<number>): void }>();
const { createMessage } = useMessage();
const { 信息, 功能, 子系统, 目录, 页面 } = MenuType;
const { 隐藏 } = MenuBehavior;
//#endregion

//#region [modal]
const modalRef = ref<VxeModalInstance>();
const modalOptions = reactive<VxeModalProps>({
  resize: true,
  destroyOnClose: true,
  escClosable: true,
  showFooter: true,
  width: 720,
  position: { top: window.innerHeight * 0.2 },
});
const modalEvents: VxeModalListeners = {
  hide() {
    page.title = "新增菜单";
    page.value = undefined;
    formData.value = { type: 页面, code: "", path: "", title: "", behavior: 隐藏, isDisabled: false };
  },
};
//#endregion

//#region [form]
const typeOptions = Object.values(MenuType)
  .map((value) => ({ value, label: MenuType[+value] }))
  .filter((o) => !!o.label);
const behaviorOptions = Object.values(MenuBehavior)
  .map((value) => ({ value, label: MenuBehavior[+value] }))
  .filter((o) => !!o.label);
const formRef = ref<VxeFormInstance>();
const formData = ref<Form<MenuInfo>>({ type: 页面, code: "", path: "", title: "", behavior: 隐藏, isDisabled: false });
const formOptions = reactive<VxeFormProps<Form<MenuInfo>>>({
  titleAlign: "right",
  titleWidth: 100,
  span: 24,
  items: [
    {
      span: 12,
      children: [
        { field: "pid", visible: false, itemRender: { name: "$input" } },
        { field: "parentName", title: "父级", itemRender: { name: "$input", props: { disabled: true } } },
        { field: "type", title: "类型", itemRender: { name: "$select", options: typeOptions, props: { placeholder: "请选择菜单类型" } } },
        {
          field: "code",
          title: "编码",
          titlePrefix: { content: "菜单关联页面对象的唯一标识" },
          itemRender: { name: "$input", props: { placeholder: "请输入菜单编码", readonly: formData.value.type === 功能 } },
        },
        { field: "title", title: "标题", itemRender: { name: "$input", props: { placeholder: "请输入菜单标题" } } },
        {
          field: "path",
          title: "路径",
          titlePrefix: {
            content:
              "菜单类型为：\n" +
              "页面、目录、子系统时，表示前端路由，例如：/sys/menu\n" +
              "功能时，表示后端接口方法+路由，如：POST /menu\n" +
              "信息时，表示信息资源链接地址，如：https://baidu.com",
          },
          itemRender: { name: "$input", props: { placeholder: "请输入路由、接口或链接地址" } },
        },
      ],
    },
    {
      span: 12,
      children: [
        { field: "icon", title: "图标", slots: { default: "item_icon" } },
        { field: "sortId", title: "显示排序", itemRender: { name: "$input", props: { type: "integer", placeholder: "请输入排序值", min: 0 } } },
        { field: "redirect", title: "跳转地址", itemRender: { name: "$input", props: { placeholder: "请输入跳转地址" } }, visibleMethod: isBranch },
        {
          field: "behavior",
          title: "行为",
          titlePrefix: {
            content:
              "未授权菜单编码关联的页面对象的渲染行为，默认为隐藏：\n" +
              "隐藏，该对象对用户不可见\n" +
              "禁用，该对象对用户可见，但处于禁用状态\n" +
              "提示，该对象对用户可见，操作会得到无权限提示",
          },
          itemRender: { name: "$radio", options: behaviorOptions },
        },
        { field: "isDisabled", title: "是否禁用", itemRender: { name: "$switch", props: { openLabel: "是", closeLabel: "否" } } },
      ],
    },
    { field: "description", title: "子系统简介", itemRender: { name: "$textarea", props: { minRows: 3, maxRows: 10 } }, visibleMethod: isSystem },
  ],
  rules: {
    type: [
      { required: true },
      {
        validator({ itemValue }) {
          if (page.parent) {
            if (page.parent.type === 页面 && itemValue !== 功能) return new Error("页面下仅能添加功能");
            if (itemValue === 子系统) return new Error("子系统类型菜单仅作为根菜单添加");
          } else {
            if (itemValue === 功能) return new Error("功能不能作为根菜单");
          }
        },
      },
    ],
    code: [{ required: true }, { max: 100, message: "菜单编码不能超过100个字符" }],
    title: [{ required: true }, { max: 100, message: "菜单标题不能超过100个字符" }],
    path: [{ required: true }, { max: 255, message: "内容不能超过255个字符" }],
    behavior: [{ required: true }],
    isDisabled: [{ required: true }],
  },
});
//#endregion

//#region [action]
function isBranch() {
  return formData.value.type === 目录 || formData.value.type === 子系统;
}
function isSystem() {
  return formData.value.type === 子系统;
}
async function open(id?: number, parent?: MenuInfo) {
  if (id) {
    const menu = await apiMenu.findById<MenuInfo>(id);
    if (!menu.value) {
      createMessage("warning", "未找到菜单，可能已经删除。");
      return;
    }
    page.value = menu.value;
    page.title = "编辑菜单";
    formData.value = menu.value;
  }

  page.parent = parent;
  page.show = true;
}
async function save() {
  const errMap = await formRef.value?.validate();
  if (!errMap) {
    let result;
    if (page.value) {
      result = await apiMenu.edit<number>(page.value.id, formData);
    } else {
      result = await apiMenu.add<number>(formData);
    }
    if (result) {
      emit("onsaved", result.value);
      close();
    }
  }
}
function close() {
  page.show = false;
}
//#endregion

defineExpose({ open });
</script>

<template>
  <vxe-modal ref="modalRef" v-model="page.show" :="modalOptions" @="modalEvents">
    <template #title>{{ page.title }}</template>
    <template #default>
      <vxe-form ref="formRef" :="formOptions" :data="formData">
        <template #item_icon="{ data }">
          <icon-picker-vue v-model="data.icon" style="width: 100%" />
        </template>
      </vxe-form>
    </template>
    <template #footer>
      <el-button type="warning" @click="save">保存</el-button>
      <el-button @click="close">取消</el-button>
    </template>
  </vxe-modal>
</template>

<style lang="scss" scoped>
:deep(.vxe-switch) {
  padding: unset;
}
</style>
